package com.lifeverse.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * 日志切面
 * 统一记录方法调用日志，包括请求参数、响应结果、执行时间等
 */
@Slf4j
@Aspect
@Component
public class LoggingAspect {
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 定义切点：Controller层的所有方法
     */
    @Pointcut("execution(* com.lifeverse.controller..*.*(..))")
    public void controllerMethods() {}
    
    /**
     * 定义切点：Service层的所有方法
     */
    @Pointcut("execution(* com.lifeverse.service..*.*(..))")
    public void serviceMethods() {}
    
    /**
     * 环绕通知：记录Controller方法的详细执行信息
     */
    @Around("controllerMethods()")
    public Object logControllerMethods(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().toShortString();
        
        // 获取HTTP请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
        
        try {
            // 记录请求开始
            if (request != null) {
                log.info("==> HTTP {} {} | Method: {} | Args: {}", 
                        request.getMethod(), 
                        request.getRequestURI(),
                        methodName,
                        formatArgs(joinPoint.getArgs()));
            } else {
                log.info("==> Method: {} | Args: {}", methodName, formatArgs(joinPoint.getArgs()));
            }
            
            // 执行方法
            Object result = joinPoint.proceed();
            
            // 记录响应结果
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("<== Method: {} | Result: {} | Time: {}ms", 
                    methodName, 
                    formatResult(result), 
                    executionTime);
            
            return result;
            
        } catch (Exception e) {
            long executionTime = System.currentTimeMillis() - startTime;
            log.error("<== Method: {} | Exception: {} | Time: {}ms", 
                    methodName, 
                    e.getMessage(), 
                    executionTime, 
                    e);
            throw e;
        }
    }
    
    /**
     * 前置通知：记录Service方法调用
     */
    @Before("serviceMethods()")
    public void logServiceMethodEntry(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().toShortString();
        log.debug("Service method called: {} with args: {}", methodName, formatArgs(joinPoint.getArgs()));
    }
    
    /**
     * 后置通知：记录Service方法返回
     */
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void logServiceMethodReturn(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().toShortString();
        log.debug("Service method returned: {} with result: {}", methodName, formatResult(result));
    }
    
    /**
     * 异常通知：记录Service方法异常
     */
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
    public void logServiceMethodException(JoinPoint joinPoint, Throwable exception) {
        String methodName = joinPoint.getSignature().toShortString();
        log.error("Service method exception: {} - {}", methodName, exception.getMessage(), exception);
    }
    
    /**
     * 格式化方法参数
     */
    private String formatArgs(Object[] args) {
        if (args == null || args.length == 0) {
            return "[]";
        }
        
        try {
            // 过滤敏感信息
            Object[] filteredArgs = Arrays.stream(args)
                    .map(this::filterSensitiveData)
                    .toArray();
            return objectMapper.writeValueAsString(filteredArgs);
        } catch (Exception e) {
            return Arrays.toString(args);
        }
    }
    
    /**
     * 格式化返回结果
     */
    private String formatResult(Object result) {
        if (result == null) {
            return "null";
        }
        
        try {
            Object filteredResult = filterSensitiveData(result);
            String resultStr = objectMapper.writeValueAsString(filteredResult);
            // 限制日志长度
            return resultStr.length() > 500 ? resultStr.substring(0, 500) + "..." : resultStr;
        } catch (Exception e) {
            return result.toString();
        }
    }
    
    /**
     * 过滤敏感数据
     */
    private Object filterSensitiveData(Object obj) {
        // 这里可以实现敏感数据过滤逻辑
        // 例如：密码、token等敏感信息
        return obj;
    }
}